package dtm

import (
	"context"
	"database/sql"
	"encoding/json"

	// "fmt"
	"strconv"
	"strings"

	"mall/common/globalkey"
	"mall/common/moneyx"
	"mall/common/mqueuex"
	"mall/common/resultx"
	"mall/service/backend/common/i18n"
	"mall/service/user/model"
	"mall/service/user/rpc/internal/svc"
	"mall/service/user/rpc/types/user"

	"github.com/dtm-labs/client/dtmcli"
	"github.com/dtm-labs/client/dtmgrpc"

	// "github.com/sirupsen/logrus"
	"github.com/volatiletech/sqlboiler/v4/boil"
	"github.com/volatiletech/sqlboiler/v4/queries/qm"
	"github.com/zeromicro/go-zero/core/logx"
)

type UpdateUserAssetRevertLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewUpdateUserAssetRevertLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateUserAssetRevertLogic {
	return &UpdateUserAssetRevertLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *UpdateUserAssetRevertLogic) UpdateUserAssetRevert(in *user.UpdateUserAssetReq) (*user.BaseResp, error) {
	// logrus.Info(fmt.Sprintf("UpdateUserAssetRevert UpdateUserAssetReq: %+v", in))
	logx.Infof("UpdateUserAssetRevert : %+v ", in)

	if in.UserId == nil || *in.UserId == 0 {
		return nil, resultx.StatusError(resultx.USER_ID_REQUIRED, "")
	}

	if in.AssetType == nil || *in.AssetType == 0 {
		return nil, resultx.StatusError(resultx.USER_ASSET_INVALID, "")
	}

	assetType := *in.AssetType

	if in.ChangeAmount == nil || len(strings.TrimSpace(*in.ChangeAmount)) == 0 {
		return nil, resultx.StatusError(resultx.USER_ASSET_INVALID, "")
	}

	var changeAmount int64
	if assetType == globalkey.UserAssetTypeGem { // 宝石
		if val, err := moneyx.ParseGem(strings.TrimSpace(*in.ChangeAmount)); err != nil || val == 0 {
			return nil, resultx.StatusError(resultx.USER_ASSET_INVALID, "")
		} else {
			changeAmount = val
		}
	} else if assetType == globalkey.UserAssetTypePoint { // 积分
		if val, err := strconv.ParseInt(strings.TrimSpace(*in.ChangeAmount), 10, 64); err != nil || val == 0 {
			return nil, resultx.StatusError(resultx.USER_ASSET_INVALID, "")
		} else {
			changeAmount = val
		}
	}

	// 获取子事务屏障对象
	barrier, err := dtmgrpc.BarrierFromGrpc(l.ctx)
	if err != nil {
		return nil, resultx.StatusError(resultx.DTM_ERROR, err.Error())
	}

	// 开启子事务屏障
	err = barrier.CallWithDB(l.svcCtx.DB, func(tx *sql.Tx) error {
		var mods []qm.QueryMod
		mods = append(mods, model.UserAccountWhere.UserID.EQ(*in.UserId))
		mods = append(mods, qm.Limit(1))
		list, err := model.UserAccounts(mods...).All(l.ctx, tx)
		if err != nil {
			if err == sql.ErrNoRows {
				return resultx.StatusError(resultx.USER_ID_INVALID, "")
			}

			return err
		}

		if len(list) == 0 {
			return resultx.StatusError(resultx.USER_ID_INVALID, "")
		}

		account := list[0]
		var changeType int64 = -1
		if in.ChangeType != nil && *in.ChangeType == globalkey.UserAssetChangeTypeDecrease {
			changeType = 1
		}

		var field string
		if assetType == globalkey.UserAssetTypeGem { // 宝石
			account.Balance = account.Balance + changeType*changeAmount
			if account.Balance < 0 {
				return dtmcli.ErrFailure
			}

			field = model.UserAccountColumns.Balance
		} else if assetType == globalkey.UserAssetTypePoint { // 积分
			account.Point = account.Point + changeType*changeAmount
			if account.Point < 0 {
				return dtmcli.ErrFailure
			}

			field = model.UserAccountColumns.Point
		}

		_, err = account.Update(l.ctx, tx, boil.Whitelist(field))
		if err != nil {
			return err
		}

		if in.SourceType != nil && in.SourceId != nil {
			var subMods []qm.QueryMod
			subMods = append(subMods, model.UserTransactionLogWhere.UserID.EQ(*in.UserId))
			subMods = append(subMods, model.UserTransactionLogWhere.AssetType.EQ(uint8(assetType)))
			subMods = append(subMods, model.UserTransactionLogWhere.Status.EQ(uint8(globalkey.StatusEnabled)))
			if in.ChangeType != nil {
				subMods = append(subMods, model.UserTransactionLogWhere.ChangeType.EQ(uint8(*in.ChangeType)))
			}
			skipTaskLog := true
			updateUserMeta := false
			skipIntegralLog := true
			if in.SourceType != nil {
				subMods = append(subMods, model.UserTransactionLogWhere.SourceType.EQ(uint8(*in.SourceType)))
				if *in.SourceId == uint64(globalkey.UserAssetSourceTypeTask) {
					skipTaskLog = false
				} else if *in.SourceType == globalkey.UserAssetSourceTypeCoupon {
					updateUserMeta = true
				} else if *in.SourceType == globalkey.UserAssetSourceTypeProduct && in.SourceDesc != nil && len(*in.SourceDesc) > 0 {
					skipIntegralLog = false
				}
			}
			if in.SourceId != nil {
				subMods = append(subMods, model.UserTransactionLogWhere.SourceID.EQ(*in.SourceId))
			}
			if in.SourceDesc != nil {
				subMods = append(subMods, model.UserTransactionLogWhere.Desc.EQ(*in.SourceDesc))
			}
			subMods = append(subMods, qm.OrderBy(model.UserTransactionLogColumns.UserTransactionLogID+" DESC"))
			subMods = append(subMods, qm.Limit(int(1)))
			_, err = model.UserTransactionLogs(subMods...).UpdateAll(l.ctx, tx, model.M{
				model.UserTransactionLogColumns.Status: uint8(globalkey.StatusExpired),
			})
			if err != nil {
				return resultx.StatusError(resultx.DB_ERROR, "")
			}

			if !skipTaskLog && in.TaskId != nil && *in.TaskId > 0 {
				var taskMods []qm.QueryMod
				taskMods = append(taskMods, model.UserTaskLogWhere.UserID.EQ(*in.UserId))
				taskMods = append(taskMods, model.UserTaskLogWhere.TaskID.EQ(*in.TaskId))
				taskMods = append(taskMods, model.UserTaskLogWhere.Status.EQ(uint8(globalkey.StatusEnabled)))
				if in.TaskName != nil {
					taskMods = append(taskMods, model.UserTaskLogWhere.TaskName.EQ(*in.TaskName))
				}
				if in.TaskSlug != nil {
					taskMods = append(taskMods, model.UserTaskLogWhere.TaskSlug.EQ(*in.TaskSlug))
				}
				if amount, err := strconv.ParseUint(*in.ChangeAmount, 10, 64); err == nil {
					taskMods = append(taskMods, model.UserTaskLogWhere.Integrals.EQ(uint(amount)))
				}
				taskMods = append(taskMods, qm.OrderBy(model.UserTaskLogColumns.ID+" DESC"))
				taskMods = append(taskMods, qm.Limit(int(1)))
				_, err = model.UserTransactionLogs(taskMods...).UpdateAll(l.ctx, tx, model.M{
					model.UserTaskLogColumns.Status: uint8(globalkey.StatusExpired),
				})
				if err != nil {
					return resultx.StatusError(resultx.DB_ERROR, "")
				}
			}

			if updateUserMeta {
				err = l.svcCtx.CurrentUser.IncreaseMeta(l.ctx, tx, *in.UserId, "_coupon_count", -1)
				if err != nil {
					if err != model.ErrNotFound {
						return resultx.StatusError(resultx.DB_ERROR, "")
					}
				}
			}

			if !skipIntegralLog {
				var product *mqueuex.ProductInfo
				if err := json.Unmarshal([]byte(strings.TrimSpace(*in.SourceDesc)), &product); err != nil {
					logx.Errorw("UpdateUserAssetRevert json.Unmarshal err", logx.Field("detail", err.Error()))
					return err
				}

				var logMods []qm.QueryMod
				logMods = append(logMods, model.UserIntegralTransactionLogWhere.UserID.EQ(*in.UserId))
				logMods = append(logMods, model.UserIntegralTransactionLogWhere.ProductID.EQ(product.ProductId))
				logMods = append(logMods, model.UserIntegralTransactionLogWhere.SkuID.EQ(product.SkuId))
				logMods = append(logMods, model.UserIntegralTransactionLogWhere.Status.EQ(uint16(globalkey.StatusEnabled)))
				logMods = append(logMods, qm.OrderBy(model.UserIntegralTransactionLogColumns.ID+" DESC"))
				logMods = append(logMods, qm.Limit(int(1)))
				_, err = model.UserIntegralTransactionLogs(logMods...).UpdateAll(l.ctx, tx, model.M{
					model.UserIntegralTransactionLogColumns.Status: uint8(globalkey.StatusExpired),
				})
				if err != nil {
					return resultx.StatusError(resultx.DB_ERROR, "")
				}
			}
		}

		return nil
	})

	if err != nil {
		return nil, err
	}

	return &user.BaseResp{
		Msg: i18n.UpdateSuccess,
	}, nil
}
